
/*********************************************************************************************************
 *  ------------------------------------------------------------------------------------------------------
 *  file description
 *  ------------------------------------------------------------------------------------------------------
 *         \file  floatl.h
 *         \unit  floatl
 *        \brief  This is a simple large float number calculate module for C language
 *       \author  Lamdonn
 *      \version  v1.1.1
 *      \license  GPL-2.0
 *    \copyright  Copyright (C) 2023 Lamdonn.
 ********************************************************************************************************/
#ifndef __floatl_H
#define __floatl_H

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include "floatl_cfg.h"

/* Version infomation */

#define FLOATL_V_MAJOR                        1
#define FLOATL_V_MINOR                        1
#define FLOATL_V_PATCH                        1

/** 
 * \brief Common constant definitions
 */

#define FLOATL_INF                            __FLOATL_INF__
#define FLOATL_INF_N                          floatl_neg(__FLOATL_INF__)
#define FLOATL_NAN                            __FLOATL_NAN__
#define FLOATL_PI                             __FLOATL_CONST_PI__
#define FLOATL_E                              __FLOATL_CONST_E__
#define FLOATL_MIN                            __FLOATL_MIN__
#define FLOATL_MAX                            __FLOATL_MAX__
#define FLOATL_EPSILON                        __FLOATL_EPSILON__
#define FLOATL_CONST_PI                       __FLOATL_CONST_PI__
#define FLOATL_CONST_E                        __FLOATL_CONST_E__
#define FLOATL_CONST_0                        __FLOATL_CONST_0__
#define FLOATL_CONST_1                        __FLOATL_CONST_1__
#define FLOATL_CONST_10                       __FLOATL_CONST_1e1__
#define FLOATL_CONST_100                      __FLOATL_CONST_1e2__
#define FLOATL_CONST_1000                     __FLOATL_CONST_1e3__
#define FLOATL_CONST_1e0                      __FLOATL_CONST_1e0__
#define FLOATL_CONST_1e1                      __FLOATL_CONST_1e1__
#define FLOATL_CONST_1e2                      __FLOATL_CONST_1e2__
#define FLOATL_CONST_1e3                      __FLOATL_CONST_1e3__
#define FLOATL_CONST_1e4                      __FLOATL_CONST_1e4__
#define FLOATL_CONST_1e5                      __FLOATL_CONST_1e5__
#define FLOATL_CONST_1e6                      __FLOATL_CONST_1e6__
#define FLOATL_CONST_1e7                      __FLOATL_CONST_1e7__
#define FLOATL_CONST_1e8                      __FLOATL_CONST_1e8__
#define FLOATL_CONST_1e9                      __FLOATL_CONST_1e9__
#define FLOATL_CONST_1e10                     __FLOATL_CONST_1e10__
#define FLOATL_CONST_1e11                     __FLOATL_CONST_1e11__
#define FLOATL_CONST_1e12                     __FLOATL_CONST_1e12__
#define FLOATL_CONST_1e13                     __FLOATL_CONST_1e13__
#define FLOATL_CONST_1e14                     __FLOATL_CONST_1e14__
#define FLOATL_CONST_1e15                     __FLOATL_CONST_1e15__

#define FLOATL_MANT_DIG                       __FLOATL_MANT_DIG__
#define FLOATL_MIN_EXP                        __FLOATL_MIN_EXP__
#define FLOATL_MAX_EXP                        __FLOATL_MAX_EXP__
#define FLOATL_DIG                            __FLOATL_DIG__
#define FLOATL_DECIMAL_DIG                    __FLOATL_DECIMAL_DIG__
#define FLOATL_MIN_10_EXP                     __FLOATL_MIN_10_EXP__
#define FLOATL_MAX_10_EXP                     __FLOATL_MAX_10_EXP__

/** 
 * \brief A structure to represent a long bits integer.
 * 
 * This structure uses a union to store the long bits integer in two different ways:
 * - An array of `__FLOATL_U16_PARTS__` uint16_t values, allowing for operations on individual 16-bit segments.
 * - An array of `__FLOATL_U32_PARTS__` uint32_t values, providing a way to work with 32-bit segments.
 * 
 * The union allows for flexibility in how the data is accessed and manipulated,
 * depending on the needs of the operations being performed.
 */
typedef struct {
    union {
        uint16_t u16[__FLOATL_U16_PARTS__];       ///< Array of uint16_t values representing the long bit integer in 16-bit segments.
        uint32_t u32[__FLOATL_U32_PARTS__];       ///< Array of uint32_t values representing the long bit integer in 32-bit segments.
        struct {
            uint32_t mantissas[__FLOATL_MANT_PARTS__];
            uint32_t mantissa : __FLOATL_MANT_HIGH_BITS__;
            uint32_t exponent : __FLOATL_EXP_BITS__;
            uint32_t sign : 1;
        };
    };
} floatl;

/** 
 * \brief floatl large integer api declaration, support for basic addition, subtraction, multiplication, division, etc.
 */

// Comparison functions
// floatl_eq: Checks if two floatl numbers are equal
// floatl_ne: Checks if two floatl numbers are not equal
// floatl_lt: Checks if the first floatl number is less than the second
// floatl_le: Checks if the first floatl number is less than or equal to the second
// floatl_gt: Checks if the first floatl number is greater than the second
// floatl_ge: Checks if the first floatl number is greater than or equal to the second

int floatl_eq(floatl a, floatl b);
int floatl_ne(floatl a, floatl b);
int floatl_lt(floatl a, floatl b);
int floatl_le(floatl a, floatl b);
int floatl_gt(floatl a, floatl b);
int floatl_ge(floatl a, floatl b);

// Arithmetic operation functions
// floatl_add: Performs addition of two floatl numbers, equivalent to the '+' operator
// floatl_sub: Performs subtraction of two floatl numbers, equivalent to the '-' operator
// floatl_mul: Performs multiplication of two floatl numbers, equivalent to the '*' operator
// floatl_div: Performs division of two floatl numbers, equivalent to the '/' operator

floatl floatl_add(floatl a, floatl b);
floatl floatl_sub(floatl a, floatl b);
floatl floatl_mul(floatl a, floatl b);
floatl floatl_div(floatl a, floatl b);

// Attribute checking functions
// floatl_sign: Determines the sign of a floatl number (returns 1 for positive, -1 for negative, 0 for zero)
// floatl_isnan: Checks if a floatl number is NaN (Not a Number)
// floatl_isinf: Checks if a floatl number is infinite
// floatl_isnormal: Checks if a floatl number is a normal number (not zero, NaN, or infinite)

int floatl_sign(floatl a);
int floatl_isnan(floatl a);
int floatl_isinf(floatl a);
int floatl_isnormal(floatl a);

// Value modification functions
// floatl_abs: Computes the absolute value of a floatl number
// floatl_neg: Computes the negation of a floatl number, equivalent to the unary '-' operator
// floatl_ceil: Computes the ceiling value of a floatl number
// floatl_floor: Computes the floor value of a floatl number
// floatl_round: Computes the round value of a floatl number

floatl floatl_abs(floatl a);
floatl floatl_neg(floatl a);
floatl floatl_ceil(floatl a);
floatl floatl_floor(floatl a);
floatl floatl_round(floatl a);

// Conversion functions
// floatl_from: Converts a string to a floatl number
// floatl_from_d: Converts a double-precision floating-point number (double) to a floatl number
// floatl_to_d: Converts a floatl to a double-precision floating-point number (double) number

floatl floatl_from(const char *str);
floatl floatl_from_d(double value);
double floatl_to_d(floatl a);

// Output function
// Converts a floatl number to a string according to the specified format and stores it in the buffer

int floatl_print(floatl a, char *buffer, uint32_t size, const char *format);

/** 
 * \brief Converts an integer to a 'floatl' number.
 * 
 * This macro provides a convenient way to convert an integer value to a 'floatl' type number.
 * It simply calls the 'floatl_from_d' function, which is assumed to be defined elsewhere,
 * to perform the actual conversion.
 * 
 * \param[in] value: The integer value to be converted to a 'floatl' number.
 * \return The corresponding 'floatl' number initialized with the given integer value.
 */
#define floatl(value)                       floatl_from_d(value)

/**
 * \brief A macro to convert a 'floatl' number to a string and handle potential conversion errors.
 * 
 * This macro uses the 'floatl_print' function to convert a 'floatl' number 'a' to a string and
 * store it in the buffer 'b' with a given buffer size 's' according to the format string 'f'.
 * If the conversion is successful (i.e., 'floatl_print' returns a value greater than 0), it returns
 * the pointer to the buffer 'b' containing the converted string. Otherwise, it returns the string
 * "invalid" to indicate that the conversion was not successful.
 * 
 * \param a: The 'floatl' number to be converted.
 * \param b: A pointer to the buffer where the converted string will be stored.
 * \param s: The size of the buffer 'b'.
 * \param f: A printf-like format string specifying how the 'floatl' number should be formatted.
 * \return A pointer to the buffer 'b' if the conversion is successful; otherwise, a pointer to the
 *         string literal "invalid".
 */
#define floatl_show(a, b, s, f)             (floatl_print((a), (b), (s), (f)) > 0 ? (b) : "invalid")

#endif

